home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / othergnu / ispell.zoo / ispell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-19  |  26.4 KB  |  1,370 lines

  1. /* -*- Mode:Text -*- */
  2.  
  3. #define MAIN
  4.  
  5. /*
  6.  * ispell.c - An interactive spelling corrector.
  7.  *
  8.  * Copyright (c), 1983, by Pace Willisson
  9.  * Permission for non-profit use is hereby granted.
  10.  * All other rights reserved.
  11.  *
  12.  * 1987, Robert McQueer, added:
  13.  *    -w option & handling of extra legal word characters
  14.  *    -d option for alternate dictionary file
  15.  *    -p option & WORDLIST variable for alternate personal dictionary
  16.  *    -x option to suppress .bak files.
  17.  *    8 bit text & config.h parameters
  18.  * 1987, Geoff Kuenning, added:
  19.  *    -c option for creating suffix suggestions from raw words
  20.  *    suffixes in personal dictionary file
  21.  *    hashed personal dictionary file
  22.  *    -S option for unsorted word lists
  23.  * 1987, Greg Schaffer, added:
  24.  *    -T option (for TeX and LaTeX instead of troff) [later changed to -t]
  25.  *       passes over \ till next whitespace.
  26.  *       does not recognize % (comment)
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <sys/param.h>
  32. #if defined(USG) || defined(atarist)
  33. #include <sys/types.h>
  34. #endif
  35. #include <sys/stat.h>
  36. #include "config.h"
  37. #include "ispell.h"
  38. #include "version.h"
  39.  
  40. #define ISTEXTERM(c)   (((c) == '{') || \
  41.             ((c) == '}') || \
  42.             ((c) == '[') || \
  43.             ((c) == ']'))
  44.  
  45. FILE *infile;
  46. FILE *outfile;
  47.  
  48. char hashname[MAXPATHLEN];
  49.  
  50. extern struct dent *treeinsert();
  51. extern char *upcase ();
  52. extern char *lowcase ();
  53.  
  54. extern char *rindex();
  55. extern char *strcpy ();
  56.  
  57. /*
  58. ** we use extended character set range specifically to allow intl.
  59. ** character set characters.  We are being REALLY paranoid about indexing
  60. ** this array - explicitly cast into unsigned INTEGER, then mask
  61. ** If NO8BIT is set, text will be masked to ascii range.
  62. */
  63. static int Trynum;
  64. #ifdef NO8BIT
  65. static char Try[128];
  66. static char Checkch[128];
  67. #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
  68. #else
  69. static char Try[256];
  70. static char Checkch[256];
  71. #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
  72. #endif
  73.  
  74. static int sortit = 1;
  75.  
  76. givehelp ()
  77. {
  78.     erase ();
  79.     printf ("Whenever a word is found that is not in the dictionary,\r\n");
  80.     printf ("it is printed on the first line of the screen.  If the dictionary\r\n");
  81.     printf ("contains any similar words, they are listed with a single digit\r\n");
  82.     printf ("next to each one.  You have the option of replacing the word\r\n");
  83.     printf ("completely, or choosing one of the suggested words.\r\n");
  84.     printf ("\r\n");
  85.     printf ("Commands are:\r\n\r\n");
  86.     printf ("R       Replace the misspelled word completely.\r\n");
  87.     printf ("Space   Accept the word this time only\r\n");
  88.     printf ("A       Accept the word for the rest of this file.\r\n");
  89.     printf ("I       Accept the word, and put it in your private dictionary.\r\n");
  90.     printf ("0-9     Replace with one of the suggested words.\r\n");
  91.     printf ("L       Look up words in system dictionary.\r\n");
  92.     printf ("Q       Write the rest of this file, ignoring misspellings, ");
  93.     printf (         "and start next file.\r\n");
  94.     printf ("X       Exit immediately.  Asks for confirmation.  ");
  95.     printf (         "Leaves file unchanged.\r\n");
  96.     printf ("!       Shell escape.\r\n");
  97.     printf ("^L      Redraw screen.\r\n");
  98.     printf ("\r\n\r\n");
  99.     printf ("-- Type space to continue --");
  100.     fflush (stdout);
  101.     while (getchar () != ' ')
  102.         ;
  103. }
  104.  
  105.  
  106. char *getline();
  107.  
  108. int cflag = 0;
  109. int lflag = 0;
  110. int incfileflag = 0;
  111. int aflag = 0;
  112. int fflag = 0;
  113. #if !defined(USG) && !defined(atarist)
  114. int sflag = 0;
  115. #endif
  116. int xflag = 0;
  117. int tflag = 0;
  118.  
  119. char *askfilename;
  120.  
  121. static char *Cmd;
  122.  
  123. usage ()
  124. {
  125.     fprintf (stderr,
  126.         "Usage: %s [-dfile | -pfile | -wchars | -t | -x | -S] file .....\n",
  127.         Cmd);
  128.     fprintf (stderr,
  129.         "       %s [-dfile | -pfile | -wchars | -t] -l\n",
  130.         Cmd);
  131. #if !defined(USG) && !defined(atarist)
  132.     fprintf (stderr,
  133.         "       %s [-dfile | -pfile | -ffile | -t | -s] {-a | -A}\n",
  134.         Cmd);
  135. #else
  136.     fprintf (stderr,
  137.         "       %s [-dfile | -pfile | -ffile | -t] {-a | -A}\n",
  138.         Cmd);
  139. #endif
  140.     fprintf (stderr, "       %s [-wchars] -c\n", Cmd);
  141.     fprintf (stderr, "       %s -v\n", Cmd);
  142.     exit (1);
  143. }
  144.  
  145. static initckch()
  146. {
  147.     register int c;
  148.  
  149.     Trynum = 0;
  150. #ifdef NO8BIT
  151.     for (c = 0; c < 128; ++c) {
  152. #else
  153.     for (c = 0; c < 256; ++c) {
  154. #endif
  155.         if (myalpha((char) c)) {
  156.             Checkch[c] = (char) 1;
  157.             if (myupper((char) c)) {
  158.                 Try[Trynum] = (char) c;
  159.                 ++Trynum;
  160.             }
  161.         }
  162.         else
  163.             Checkch[c] = (char) 0;
  164.     }
  165. }
  166.  
  167. main (argc, argv)
  168. char **argv;
  169. {
  170.     char *p;
  171.     char *cpd;
  172.     char num[4];
  173.     unsigned mask;
  174.     static char outbuf[BUFSIZ];
  175.     extern char *getenv();
  176.  
  177.     Cmd = *argv;
  178.  
  179.     initckch();
  180. #ifdef atarist
  181.     if((p = getenv("LIB")) != NULL)
  182.         sprintf(hashname,"%s/%s",p,DEFHASH);
  183.     else
  184. #endif
  185.         sprintf(hashname,"%s/%s",LIBDIR,DEFHASH);
  186.  
  187.     cpd = NULL;
  188.  
  189.     argv++;
  190.     argc--;
  191.     while (argc && **argv == '-') {
  192.         switch ((*argv)[1]) {
  193.         case 'v':
  194.             printf ("%s\n", Version_ID);
  195.             exit (0);
  196.         case 't':
  197.             tflag++;
  198.             break;
  199.         case 'A':
  200.             incfileflag = 1;
  201.             aflag = 1;
  202.             break;
  203.         case 'a':
  204.             aflag++;
  205.             break;
  206.         case 'c':
  207.             cflag++;
  208.             lflag++;
  209.             break;
  210.         case 'x':
  211.             xflag++;
  212.             break;
  213.         case 'f':
  214.             fflag++;
  215.             p = (*argv)+2;
  216.             if (*p == '\0') {
  217.                 argv++; argc--;
  218.                 if (argc == 0)
  219.                     usage ();
  220.                 p = *argv;
  221.             }
  222.             askfilename = p;
  223.             break;
  224.         case 'l':
  225.             lflag++;
  226.             break;
  227. #if !defined(USG) && !defined(atarist)
  228.         case 's':
  229.             sflag++;
  230.             break;
  231. #endif
  232.         case 'S':
  233.             sortit = 0;
  234.             break;
  235.         case 'p':
  236.             cpd = (*argv)+2;
  237.             if (*cpd == '\0') {
  238.                 argv++; argc--;
  239.                 if (argc == 0)
  240.                     usage ();
  241.                 cpd = *argv;
  242.             }
  243.             break;
  244.         case 'd':
  245.             p = (*argv)+2;
  246.             if (*p == '\0') {
  247.                 argv++; argc--;
  248.                 if (argc == 0)
  249.                     usage ();
  250.                 p = *argv;
  251.             }
  252.             if (*p == '/')
  253.                 strcpy(hashname,p);
  254.             else
  255.                 sprintf(hashname,"%s/%s",LIBDIR,p);
  256.             break;
  257.         case 'w':
  258.             num[3] = '\0';
  259. #ifdef NO8BIT
  260.             mask = 0x7f;
  261. #else
  262.             mask = 0xff;
  263. #endif
  264.             p = (*argv)+2;
  265.             if (*p == '\0') {
  266.                 argv++; argc--;
  267.                 if (argc == 0)
  268.                     usage ();
  269.                 p = *argv;
  270.             }
  271.             while (Trynum <= mask && *p != '\0') {
  272.                 if (*p != 'n'  &&  *p != '\\') {
  273.                     Checkch[((unsigned)(*p))&mask] = (char) 1;
  274.                     Try[Trynum] = *p & mask;
  275.                     ++p;
  276.                 }
  277.                 else {
  278.                     ++p;
  279.                     num[0] = '\0'; 
  280.                     num[1] = '\0'; 
  281.                     num[2] = '\0'; 
  282.                     num[3] = '\0';
  283.                     if (isdigit (p[0]))
  284.                         num[0] = p[0];
  285.                     if (isdigit (p[1]))
  286.                         num[1] = p[1];
  287.                     if (isdigit (p[2]))
  288.                         num[2] = p[2];
  289.                     if (p[-1] == 'n') {
  290.                         p += strlen (num);
  291.                         num[0] = atoi (num);
  292.                     }
  293.                     else {
  294.                         p += strlen (num);
  295.                         if (num[0])
  296.                             num[0] -= '0';
  297.                         if (num[1]) {
  298.                             num[0] <<= 3;
  299.                             num[0] += num[1] - '0';
  300.                         }
  301.                         if (num[2]) {
  302.                             num[0] <<= 3;
  303.                             num[0] += num[2] - '0';
  304.                         }
  305.                     }
  306.                     Try[Trynum] = num[0] & mask;
  307.                     Checkch[num[0] & mask] = 1;
  308.                 }
  309.                 ++Trynum;
  310.             }
  311.             break;
  312.         default:
  313.             usage();
  314.         }
  315.         argv++; argc--;
  316.     }
  317.  
  318.     if (!argc && !lflag && !aflag)
  319.         usage ();
  320.  
  321.     if (linit () < 0)
  322.         exit (0);
  323.  
  324.     treeinit (cpd);
  325.  
  326.     if (aflag) {
  327.         askmode ();
  328.         exit (0);
  329.     }
  330.  
  331.     setbuf (stdout, outbuf);
  332.     if (lflag) {
  333.         infile = stdin;
  334.         checkfile ();
  335.         exit (0);
  336.     }
  337.  
  338.     terminit ();
  339.  
  340.     while (argc--)
  341.         dofile (*argv++);
  342.  
  343.     done ();
  344. }
  345.  
  346. char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
  347. char *currentchar;
  348. char token[BUFSIZ];
  349.  
  350. int quit;
  351.  
  352. char *currentfile = NULL;
  353.  
  354. dofile (filename)
  355. char *filename;
  356. {
  357.     int c;
  358.     char    bakfile[256];
  359.     struct stat statbuf;
  360.     char *cp;
  361.  
  362.     currentfile = filename;
  363.  
  364.     if ((infile = fopen (filename, "r")) == NULL) {
  365.         fprintf (stderr, "Can't open %s\r\n", filename);
  366.         sleep (2);
  367.         return;
  368.     }
  369.  
  370.     if (access (filename, 2) < 0) {
  371.         fprintf (stderr, "Can't write to %s\r\n", filename);
  372.         sleep (2);
  373.         return;
  374.     }
  375.  
  376.     fstat (fileno (infile), &statbuf);
  377. #ifdef atarist
  378.     {
  379.       char *p, c;
  380.       extern char *getenv();
  381.  
  382.       if((p = getenv("TEMP")) != NULL)
  383.       {
  384.           strcpy(tempfile, p);
  385.           c = p[(strlen(p) - 1)];
  386.           if((c != '/') || (c != '\\'))
  387.         strcat(tempfile,"/");
  388.       }
  389.     }
  390. #endif    
  391.     strcpy(tempfile, TEMPNAME);
  392.     mktemp (tempfile);
  393.     chmod (tempfile, statbuf.st_mode);
  394.     if ((outfile = fopen (tempfile, "w")) == NULL) {
  395.         fprintf (stderr, "Can't create %s\r\n", tempfile);
  396.         sleep (2);
  397.         return;
  398.     }
  399.  
  400.     quit = 0;
  401.  
  402.     /* See if the file is a .tex file.  If so, set the appropriate flag. */
  403.     if ((cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0)
  404.         tflag = 1;
  405.     checkfile ();
  406.  
  407.     fclose (infile);
  408.     fclose (outfile);
  409.  
  410.     if (!cflag)
  411.         treeoutput ();
  412.  
  413.     if ((infile = fopen (tempfile, "r")) == NULL) {
  414.         fprintf (stderr, "temporary file disappeared (%s)\r\n", tempfile);    
  415.         sleep (2);
  416.         return;
  417.     }
  418.  
  419. #ifndef atarist
  420.     sprintf(bakfile, "%s%s", filename, BAKEXT);
  421.     if(link(filename, bakfile) == 0)
  422.         unlink(filename);
  423. #else
  424.     {
  425.       char *p;
  426.       strcpy(bakfile, filename);
  427.       p = rindex(bakfile, '.');
  428.       if(p != NULL)
  429.       {
  430.         *p = '\0';
  431.         strcat(bakfile, BAKEXT);
  432.       }
  433.       else
  434.       {
  435.         strcat(bakfile, ".");
  436.         strcat(bakfile, BAKEXT);
  437.       }
  438.       rename(filename, bakfile);
  439.     }
  440. #endif
  441.  
  442.     /* if we can't write new, preserve .bak regardless of xflag */
  443.     if ((outfile = fopen (filename, "w")) == NULL) {
  444.         fprintf (stderr, "can't create %s\r\n", filename);
  445.         sleep (2);
  446.         return;
  447.     }
  448.  
  449.     chmod (filename, statbuf.st_mode);
  450.  
  451.     while ((c = getc (infile)) != EOF)
  452.         putc (c, outfile);
  453.  
  454.     fclose (infile);
  455.     fclose (outfile);
  456.  
  457.     unlink (tempfile);
  458.     if (xflag)
  459.         unlink(bakfile);
  460. }
  461.  
  462. checkfile ()
  463. {
  464.     register int c;
  465.     register char *p;
  466.     register int len;
  467.  
  468.     secondbuf[0] = 0;
  469.  
  470.     while (1) {
  471.         strcpy (firstbuf, secondbuf);
  472.         if (quit) {    /* quit can't be set in l mode */
  473.             while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
  474.                 fputs (secondbuf, outfile);
  475.             break;
  476.         }
  477.  
  478.         if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
  479.             break;
  480.         currentchar = secondbuf;
  481.         
  482.         len = strlen (secondbuf) - 1;
  483.  
  484.         if(!tflag) {
  485.             /* skip over .if */
  486.             if (strncmp(currentchar,".if t",5) == 0 
  487.             ||  strncmp(currentchar,".if n",5) == 0) {
  488.                 copyout(¤tchar,5);
  489.                 while (*currentchar && isspace(*currentchar)) 
  490.                     copyout(¤tchar, 1);
  491.             }
  492.  
  493.             /* skip over .ds XX or .nr XX */
  494.             if (strncmp(currentchar,".ds ",4) == 0 
  495.             ||  strncmp(currentchar,".de ",4) == 0
  496.             ||  strncmp(currentchar,".nr ",4) == 0) {
  497.                 copyout(¤tchar, 3);
  498.                 while (*currentchar && isspace(*currentchar)) 
  499.                     copyout(¤tchar, 1);
  500.                 while (*currentchar && !isspace(*currentchar))
  501.                     copyout(¤tchar, 1);
  502.                 if (*currentchar == 0) {
  503.                     if (!lflag) putc ('\n', outfile);
  504.                     continue;
  505.                 }
  506.             }
  507.         }
  508.  
  509.         if (secondbuf [ len ] == '\n')
  510.             secondbuf [ len ] = 0;
  511.  
  512.         /* if this is a formatter command, skip over it */
  513.         if (!tflag && *currentchar == '.') {
  514.             while (*currentchar && !myspace (*currentchar)) {
  515.                 if (!lflag)
  516.                     putc (*currentchar, outfile);
  517.                 currentchar++;
  518.             }
  519.             if (*currentchar == 0) {
  520.                 if (!lflag)
  521.                     putc ('\n', outfile);
  522.                 continue;
  523.             }
  524.         }
  525.  
  526.         while (1) {
  527.             while (*currentchar && !iswordch(*currentchar)) {
  528.                 if (tflag)        /* TeX or LaTeX stuff */
  529.                 {
  530.                 if (*currentchar == '\\') {
  531.                     /* skip till whitespace */
  532.                     while (*currentchar && 
  533.                     (!isspace(*currentchar) &&
  534.                      !ISTEXTERM(*currentchar))) {
  535.                         if (!lflag)
  536.                         putc(*currentchar, outfile);
  537.                         currentchar++;
  538.                     }
  539.                     continue;
  540.                 }
  541.                 }
  542.                 else
  543.                 {
  544.                 /* formatting escape sequences */
  545.                 if (*currentchar == '\\') {
  546.                 switch ( currentchar [1] ) {
  547.                 case 'f':
  548.                     if(currentchar[2] != '(') {
  549.                         /* font change: \fX */
  550.                         copyout(¤tchar, 3);
  551.                     }
  552.                     else {
  553.                         /* font change: \f(XY */
  554.                         copyout(¤tchar, 5);
  555.                     }
  556.                     continue;
  557.                 case 's':
  558.                     /* size change */
  559.                     p = currentchar + 2;
  560.                     if (*p == '+'  ||  *p == '-')
  561.                         p++;
  562.                     /* This looks wierd 'cause we assume
  563.                     ** *p is now a digit.
  564.                     */
  565.                     if (isdigit (p[1]))
  566.                         p++;
  567.                     copyout (¤tchar,
  568.                             p - currentchar + 1);
  569.                     continue;
  570.                 case '(':
  571.                     /* extended char set escape: \(XX */
  572.                     copyout(¤tchar, 4);
  573.                     continue;
  574.                 case '*':
  575.                     if ( currentchar[2] != '(' )
  576.                         copyout(¤tchar, 3);
  577.                     else
  578.                         copyout(¤tchar, 5);
  579.                     continue;
  580.                 default:
  581.                     break;
  582.                     }
  583.                 }
  584.                 }
  585.  
  586.                 if (!lflag)
  587.                     putc (*currentchar, outfile);
  588.                 currentchar++;
  589.             }
  590.  
  591.             if (*currentchar == 0)
  592.                 break;
  593.  
  594.             p = token;
  595.             while (iswordch(*currentchar) ||
  596.                    (*currentchar == '\'' &&
  597.                 iswordch(*(currentchar + 1))))
  598.               *p++ = *currentchar++;
  599.             *p = 0;
  600.             if (lflag) {
  601.                 if (!good (token)  &&  !cflag)
  602.                     printf ("%s\n", token);
  603.             } else {
  604.                 if (!quit)
  605.                 correct (token, ¤tchar);
  606.             }
  607.             if (!lflag)
  608.                 fprintf (outfile, "%s", token);
  609.         }
  610.         if (!lflag)
  611.             putc ('\n', outfile);
  612.     }
  613. }
  614.  
  615. #define MAXPOSSIBLE    100    /* Max no. of possibilities to generate */
  616.  
  617. char possibilities[MAXPOSSIBLE][BUFSIZ];
  618. int pcount;
  619. int maxposslen;
  620.  
  621. correct (token, currentchar)
  622. char *token;
  623. char **currentchar;
  624. {
  625.     register int c;
  626.     register int i;
  627.     int col_ht;
  628.     int ncols;
  629.     register char *p;
  630.     char *start_l2;
  631.     char *begintoken;
  632.  
  633.     begintoken = *currentchar - strlen (token);
  634.  
  635. checkagain:
  636.     if (good (token))
  637.         return;
  638.  
  639.     erase ();
  640.     printf ("    %s", token);
  641.     if (currentfile)
  642.         printf ("              File: %s", currentfile);
  643.     printf ("\r\n\r\n");
  644.  
  645.     makepossibilities (token);
  646.  
  647.     /*
  648.      * Make sure we have enough room on the screen to hold the
  649.      * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
  650.      * is the maximum number of columns that will fit.
  651.      */
  652.     col_ht = li - 6;        /* Height of columns of words */
  653.     ncols = co / (maxposslen + 8);
  654.     if (pcount > ncols * col_ht)
  655.         pcount = ncols * col_ht;
  656.  
  657. #ifdef EQUAL_COLUMNS
  658.     /*
  659.      * Equalize the column sizes.  The last column will be short.
  660.      */
  661.     col_ht = (pcount + ncols - 1) / ncols;
  662. #endif
  663.  
  664.     for (i = 0; i < pcount; i++) {
  665.         move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  666.         printf ("%2d: %s", i, possibilities[i]);
  667.     }
  668.  
  669.     move (li - 3, 0);
  670.     show_line (firstbuf, firstbuf, 0);
  671.  
  672.     start_l2 = secondbuf;
  673.     if (line_size (secondbuf, *currentchar) > co - 1) {
  674.         start_l2 = begintoken - (co / 2);
  675.         while (start_l2 < begintoken) {
  676.             i = line_size (start_l2, *currentchar) + 1;
  677.             if (i <= co)
  678.                 break;
  679.             start_l2 += i - co;
  680.         }
  681.         if (start_l2 > begintoken)
  682.             start_l2 = begintoken;
  683.         if (start_l2 < secondbuf)
  684.             start_l2 = secondbuf;
  685.     }
  686.     show_line (start_l2, begintoken, strlen (token));
  687.  
  688.  
  689.     while (1) {
  690.         fflush (stdout);
  691.         switch (c = (getchar () & NOPARITY)) {
  692. #if !defined(USG) && !defined(atarist)
  693.         case 'Z' & 037:
  694.             stop ();
  695.             erase ();
  696.             goto checkagain;
  697. #endif
  698.         case ' ':
  699.             erase ();
  700.             fflush (stdout);
  701.             return;
  702.         case 'x': case 'X':
  703.             printf ("Are you sure you want to throw away your changes? ");
  704.             fflush (stdout);
  705.             c = (getchar () & NOPARITY);
  706.             if (c == 'y' || c == 'Y') {
  707.                 erase ();
  708.                 fflush (stdout);
  709.                 done ();
  710.             }
  711.             putchar (7);
  712.             goto checkagain;
  713.         case 'i': case 'I':
  714.             treeinsert (token, 1);
  715.             erase ();
  716.             fflush (stdout);
  717.             return;
  718.         case 'a': case 'A':
  719.             treeinsert (token, 0);
  720.             erase ();
  721.             fflush (stdout);
  722.             return;
  723.         case 'L' & 037:
  724.             goto checkagain;
  725.         case '?':
  726.             givehelp ();
  727.             goto checkagain;
  728.         case '!':
  729.             {
  730.                 char buf[200];
  731.                 move (li - 1, 0);
  732.                 putchar ('!');
  733.                 if (getline (buf) == NULL) {
  734.                     putchar (7);
  735.                     erase ();
  736.                     fflush (stdout);
  737.                     goto checkagain;
  738.                 }
  739.                 printf ("\r\n");
  740.                 fflush (stdout);
  741.                 shellescape (buf);
  742.                 erase ();
  743.                 goto checkagain;
  744.             }
  745.         case 'r': case 'R':
  746.             move (li - 1, 0);
  747.             printf ("Replace with: ");
  748.             if (getline (token) == NULL) {
  749.                 putchar (7);
  750.                 erase ();
  751.                 goto checkagain;
  752.             }
  753.             inserttoken (secondbuf, begintoken, token, currentchar);
  754.             erase ();
  755.             goto checkagain;
  756.         case '0': case '1': case '2': case '3': case '4':
  757.         case '5': case '6': case '7': case '8': case '9':
  758.             i = c - '0';
  759.             if (pcount > 10
  760.                 &&  i > 0  &&  i <= (pcount - 1) / 10) {
  761.                 c = getchar () & NOPARITY;
  762.                 if (c >= '0'  &&  c <= '9')
  763.                     i = i * 10 + c - '0';
  764.                 else if (c != '\r'  &&  c != '\n') {
  765.                     putchar (7);
  766.                     break;
  767.                 }
  768.             }
  769.             if (i < pcount) {
  770.                 strcpy (token, possibilities[i]);
  771.                 inserttoken (secondbuf, begintoken,
  772.                     token, currentchar);
  773.                 erase ();
  774.                 return;
  775.             }
  776.             putchar (7);
  777.             break;
  778.         case '\r':    /* This makes typing \n after single digits */
  779.         case '\n':    /* ..less obnoxious */
  780.             break;
  781.         case 'l': case 'L':
  782.             {
  783.                 char buf[100];
  784.                 move (li - 1, 0);
  785.                 printf ("Lookup string ('*' is wildcard): ");
  786.                 if (getline (buf) == NULL) {
  787.                     putchar (7);
  788.                     erase ();
  789.                     goto checkagain;
  790.                 }
  791.                 printf ("\r\n\r\n");
  792.                 fflush (stdout);
  793.                 lookharder (buf);
  794.                 erase ();
  795.                 goto checkagain;
  796.             }
  797.         case 'q': case 'Q':
  798.             quit = 1;
  799.             erase ();
  800.             fflush (stdout);
  801.             return;
  802.         default:
  803.             putchar (7);
  804.             break;
  805.         }
  806.     }
  807. }
  808.  
  809. show_line (line, invstart, invlen)
  810. register char *line;
  811. register char *invstart;
  812. register int invlen;
  813. {
  814.     register int width;
  815.  
  816.     width = 0;
  817.     while (line != invstart  &&  width < co - 1)
  818.         width += show_char (*line++, width);
  819.     if (invlen) {
  820.         inverse ();
  821.         while (--invlen >= 0  &&  width < co - 1)
  822.             width += show_char (*line++, width);
  823.         normal ();
  824.     }
  825.     while (*line  &&  width < co - 1)
  826.         width += show_char (*line++, width);
  827.     printf ("\r\n");
  828. }
  829.  
  830. show_char (ch, linew)
  831. register int ch;
  832. int linew;
  833. {
  834.     if (ch == '\t') {
  835.         putchar ('\t');
  836.         return 8 - (linew & 0x07);
  837.     }
  838.     else if (ch < ' ') {
  839.         putchar ('^');
  840.         putchar (ch + 'A' - '\001');
  841.         return 2;
  842.     }
  843.     putchar (ch);
  844.     return 1;
  845. }
  846.  
  847. line_size (buf, bufend)
  848. register char *buf;
  849. register char *bufend;
  850. {
  851.     register int width;
  852.  
  853.     for (width = 0;  buf < bufend  &&  *buf;  buf++) {
  854.         if (*buf == '\t')
  855.             width = (width + 8) & ~0x07;
  856.         else if (*buf < ' ')
  857.             width += 2;
  858.         else
  859.             width++;
  860.     }
  861.     return width;
  862. }
  863.  
  864. inserttoken (buf, start, token, currentchar)
  865. char *buf, *start; 
  866. register char *token;
  867. char **currentchar;
  868. {
  869.     char copy[BUFSIZ];
  870.     register char *p, *q;
  871.  
  872.     strcpy (copy, buf);
  873.  
  874.     for (p = buf, q = copy; p != start; p++, q++)
  875.         *p = *q;
  876.     q += *currentchar - start;
  877.     while (*token  &&  iswordch (*token))
  878.         *p++ = *token++;
  879.     *currentchar = p;
  880.     if (*token) {
  881.  
  882.         /*
  883.         ** The token changed to two words.  Split it up and save the
  884.         ** second one for later.
  885.         */
  886.  
  887.         *p++ = *token;
  888.         *token++ = '\0';
  889.         while (*token)
  890.             *p++ = *token++;
  891.     }
  892.     while (*p++ = *q++)
  893.         ;
  894. }
  895.  
  896. int casecmp (a, b)
  897. char *a;
  898. char *b;
  899. {
  900.     register char *ap;
  901.     register char *bp;
  902.  
  903.     for (ap = a, bp = b;  *ap;  ap++, bp++) {
  904.         if (mylower (*ap)) {
  905.             if (mylower (*bp)) {
  906.                 if (*ap != *bp)
  907.                     return *ap - *bp;
  908.             }
  909.             else {
  910.                 if (toupper (*ap) != *bp)
  911.                     return toupper (*ap) - *bp;
  912.             }
  913.         }
  914.         else {
  915.             if (myupper (*bp)) {
  916.                 if (*ap != *bp)
  917.                     return *ap - *bp;
  918.             }
  919.             else {
  920.                 if (tolower (*ap) != *bp)
  921.                     return tolower (*ap) - *bp;
  922.             }
  923.         }
  924.     }
  925.     if (*bp != '\0')
  926.         return -*bp;
  927.     return strcmp (a, b);
  928. }
  929.  
  930. makepossibilities (word)
  931. register char *word;
  932. {
  933.     register int i;
  934.  
  935.     for (i = 0; i < MAXPOSSIBLE; i++)
  936.         possibilities[i][0] = 0;
  937.     pcount = 0;
  938.     maxposslen = 0;
  939.  
  940. #ifdef CAPITALIZE
  941.     wrongcapital (word);
  942. #endif
  943.     if (pcount < MAXPOSSIBLE) wrongletter (word);
  944.     if (pcount < MAXPOSSIBLE) extraletter (word);
  945.     if (pcount < MAXPOSSIBLE) missingletter (word);
  946.     if (pcount < MAXPOSSIBLE) transposedletter (word);
  947.  
  948.     if (sortit  &&  pcount)
  949.         qsort ((char *) possibilities, pcount,
  950.             sizeof (possibilities[0]), casecmp);
  951. }
  952.  
  953. insert (word)
  954. register char *word;
  955. {
  956.     register int i;
  957.  
  958.     for (i = 0; i < pcount; i++)
  959.         if (strcmp (possibilities[i], word) == 0)
  960.             return (0);
  961.  
  962.     strcpy (possibilities[pcount++], word);
  963.     i = strlen (word);
  964.     if (i > maxposslen)
  965.         maxposslen = i;
  966.     if (pcount >= MAXPOSSIBLE)
  967.         return (-1);
  968.     else
  969.         return (0);
  970. }
  971.  
  972. #ifdef CAPITALIZE
  973. wrongcapital (word)
  974. register char *word;
  975. {
  976.     char newword[BUFSIZ];
  977.  
  978.     /*
  979.     ** All-uppercase is always legal.  If the word matches, "ins_cap"
  980.     ** will recapitalize it correctly.
  981.     */
  982.     strcpy (newword, word);
  983.     upcase (newword);
  984.     if (good (newword))
  985.         return ins_cap (newword, word);
  986.     return 0;
  987. }
  988. #endif
  989.  
  990. wrongletter (word)
  991. register char *word;
  992. {
  993.     register int i, j, c, n;
  994.     char newword[BUFSIZ];
  995.  
  996.     n = strlen (word);
  997.     strcpy (newword, word);
  998. #ifdef CAPITALIZE
  999.     upcase (newword);
  1000. #endif
  1001.  
  1002.     for (i = 0; i < n; i++) {
  1003.         for (j=0; j < Trynum; ++j) {
  1004.             newword[i] = Try[j];
  1005.             if (good (newword)) {
  1006.                 if (ins_cap (newword, word) < 0)
  1007.                     return;
  1008.             }
  1009.         }
  1010. #ifdef CAPITALIZE
  1011.         c = word[i];
  1012.         if (islower (c))
  1013.             newword[i] = toupper (c);
  1014.         else
  1015.             newword[i] = c;
  1016. #else
  1017.         newword[i] = word[i];
  1018. #endif
  1019.     }
  1020. }
  1021.  
  1022. extraletter (word)
  1023. register char *word;
  1024. {
  1025.     char newword[BUFSIZ];
  1026.     register char *p, *s, *t;
  1027.  
  1028.     if (strlen (word) < 3)
  1029.         return;
  1030.  
  1031.     for (p = word; *p; p++) {
  1032.         for (s = word, t = newword; *s; s++)
  1033.             if (s != p)
  1034.                 *t++ = *s;
  1035.         *t = 0;
  1036. #ifdef CAPITALIZE
  1037.         if (good (upcase (newword))) {
  1038.             if (ins_cap (newword, word) < 0)
  1039.                 return;
  1040.         }
  1041. #else
  1042.         if (good (newword)) {
  1043.             if (ins_cap (newword, word) < 0)
  1044.                 return;
  1045.         }
  1046. #endif
  1047.     }
  1048. }
  1049.  
  1050. missingletter (word)
  1051. char word[];
  1052. {
  1053.     char newword[BUFSIZ]; 
  1054.     register char *p, *r, *s, *t;
  1055.     register int i;
  1056.  
  1057.     for (p = word; p == word || p[-1]; p++) {
  1058.         for (s = newword, t = word; t != p; s++, t++)
  1059.             *s = *t;
  1060.         r = s++;
  1061.         while (*t)
  1062.             *s++ = *t++;
  1063.         *s = 0;
  1064.         for (i=0; i < Trynum; ++i) {
  1065.             *r = Try[i];
  1066. #ifdef CAPITALIZE
  1067.             if (good (upcase (newword))) {
  1068.                 if (ins_cap (newword, word) < 0)
  1069.                     return;
  1070.             }
  1071. #else
  1072.             if (good (newword)) {
  1073.                 if (ins_cap (newword, word) < 0)
  1074.                     return;
  1075.             }
  1076. #endif
  1077.         }
  1078.     }
  1079. }
  1080.  
  1081. transposedletter (word)
  1082. register char *word;
  1083. {
  1084.     char newword[BUFSIZ];
  1085.     register int t;
  1086.     register char *p;
  1087.  
  1088.     strcpy (newword, word);
  1089.     for (p = newword; p[1]; p++) {
  1090.         t = p[0];
  1091.         p[0] = p[1];
  1092.         p[1] = t;
  1093. #ifdef CAPITALIZE
  1094.         if (good (upcase (newword))) {
  1095.             if (ins_cap (newword, word) < 0)
  1096.                 return;
  1097.         }
  1098. #else
  1099.         if (good (newword)) {
  1100.             if (ins_cap (newword, word) < 0)
  1101.                 return;
  1102.         }
  1103. #endif
  1104.         t = p[0];
  1105.         p[0] = p[1];
  1106.         p[1] = t;
  1107.     }
  1108. }
  1109.  
  1110. /* Insert one or more correctly capitalized versions of pattern */
  1111. ins_cap (word, pattern)
  1112. register char *word, *pattern;
  1113. {
  1114.     static char newword[BUFSIZ];
  1115.     register char *p, *q;
  1116.     char *psave;
  1117.     register int wcount;
  1118.  
  1119.     if (*word == 0)
  1120.         return;
  1121.  
  1122.     strcpy (newword, word);
  1123. #ifdef CAPITALIZE
  1124.     if (lastdent->allcaps)
  1125.         return insert (upcase (newword)); /* Uppercase required */
  1126.     for (p = pattern;  *p;  p++)
  1127.         if (mylower (*p))
  1128.             break;
  1129.     if (*p == '\0')
  1130.         return insert (upcase (newword)); /* Pattern was all caps */
  1131.     for (p = pattern;  *p;  p++)
  1132.         if (myupper (*p))
  1133.             break;
  1134.     if (*p == '\0') {            /* Pattern was all lower */
  1135.         if (!lastdent->followcase  &&  !lastdent->capitalize)
  1136.             return insert (lowcase (newword));
  1137.         /*
  1138.         ** If there's a followcase version that's all-lower,
  1139.         ** insert only that version.
  1140.         */
  1141.         if (lastdent->followcase) {
  1142.             p = lastdent->word;
  1143.             p += strlen (p) + 1;
  1144.             wcount = (*p++ & 0xFF);
  1145.             while (--wcount >= 0) {
  1146.                 for (psave = ++p;
  1147.                     *p  &&  !myupper (*p);
  1148.                     p++)
  1149.                     ;
  1150.                 if (*p == '\0')    /* Was it all lowercase? */
  1151.                     return insert (psave);    /* Yup, quit */
  1152.                 while (*p++)
  1153.                     ;    /* Skip to next case sample */
  1154.             }
  1155.         }
  1156.     }
  1157.     /*
  1158.     ** The sample wasn't all-upper, and either it wasn't all-lower or
  1159.     ** all-lower is illegal.  Insert all legal capitalizations.  In
  1160.     ** some cases, this may include all-lowercase.
  1161.     */
  1162.     if (lastdent->capitalize) {
  1163.         lowcase (newword);
  1164.         if (mylower (newword[0]))
  1165.             newword[0] = toupper (newword[0]);
  1166.         insert (newword);
  1167.     }
  1168.     if (lastdent->followcase) {
  1169.         p = lastdent->word;
  1170.         p += strlen (p) + 1;
  1171.         wcount = (*p++ & 0xFF);
  1172.         while (--wcount >= 0) {
  1173.             /* Insert every variation;  it's easier */
  1174.             if (insert (++p) < 0)
  1175.                 return -1;
  1176.             while (*p++)
  1177.                 ;        /* Skip to end of sample */
  1178.         }
  1179.         return 0;
  1180.     }
  1181.     if (lastdent->capitalize)
  1182.         return 0;
  1183.     /*
  1184.     ** We get here only if none of the special capitalization flags are
  1185.     ** set.  If first letter of the pattern is capitalized, capitalize
  1186.     ** the first letter of the result.  Otherwise produce all lowercase.
  1187.     */
  1188.     lowcase (newword);
  1189.     if (myupper (pattern[0])  &&  mylower (newword[0]))
  1190.         newword[0] = toupper (newword[0]);
  1191.     return insert (newword);
  1192. #else
  1193.     if (myupper (pattern[0])) {
  1194.         if (myupper (pattern[1])) {
  1195.             for (p = word, q = newword; *p; p++, q++) {
  1196.                 if (mylower (*p))
  1197.                     *q = toupper (*p);
  1198.                 else
  1199.                     *q = *p;
  1200.             }
  1201.             *q = 0;
  1202.         } else {
  1203.             if (mylower (word [0]))
  1204.                 newword[0] = toupper (word[0]);
  1205.             else
  1206.                 newword[0] = word[0];
  1207.  
  1208.             for (p = word + 1, q = newword + 1; *p; p++, q++)
  1209.                 if (myupper (*p))
  1210.                     *q = tolower (*p);
  1211.                 else
  1212.                     *q = *p;
  1213.  
  1214.             *q = 0;
  1215.         }
  1216.     } else {
  1217.         for (p = word, q = newword; *p; p++, q++)
  1218.             if (myupper (*p))
  1219.                 *q = tolower (*p);
  1220.             else
  1221.                 *q = *p;
  1222.         *q = 0;
  1223.     }
  1224.     return insert (newword);
  1225. #endif
  1226. }
  1227.  
  1228. char *
  1229. getline (s)
  1230. register char *s;
  1231. {
  1232.     register char *p;
  1233.     register int c;
  1234.  
  1235.     p = s;
  1236.  
  1237.     while (1) {
  1238.         fflush (stdout);
  1239.         c = (getchar () & NOPARITY);
  1240.         if (c == '\\') {
  1241.             putchar ('\\');
  1242.             fflush (stdout);
  1243.             c = (getchar () & NOPARITY);
  1244.             backup ();
  1245.             putchar (c);
  1246.             *p++ = c;
  1247.         } else if (c == ('G' & 037)) {
  1248.             return (NULL);
  1249.         } else if (c == '\n' || c == '\r') {
  1250.             *p = 0;
  1251.             return (s);
  1252.         } else if (c == erasechar) {
  1253.             if (p != s) {
  1254.                 p--;
  1255.                 backup ();
  1256.                 putchar (' ');
  1257.                 backup ();
  1258.             }
  1259.         } else if (c == killchar) {
  1260.             while (p != s) {
  1261.                 p--;
  1262.                 backup ();
  1263.                 putchar (' ');
  1264.                 backup ();
  1265.             }
  1266.         } else {
  1267.             *p++ = c;
  1268.             putchar (c);
  1269.         }
  1270.     }
  1271. }
  1272.  
  1273. askmode ()
  1274. {
  1275.     char buf[BUFSIZ];
  1276.     register int i;
  1277.  
  1278.     if (fflag) {
  1279.         if (freopen (askfilename, "w", stdout) == NULL) {
  1280.             fprintf (stderr, "Can't create %s\n", askfilename);
  1281.             exit (1);
  1282.         }
  1283.     }
  1284.  
  1285.     setbuf (stdin, NULL);
  1286.     setbuf (stdout, NULL);
  1287.  
  1288.     while (xgets (buf) != NULL) {
  1289.         /* *line is like `i', @line is like `a' */
  1290.         if (buf[0] == '*' || buf[0] == '@') {
  1291.             treeinsert(buf + 1, buf[0] == '*');
  1292.             printf("*\n");
  1293.             treeoutput ();
  1294.         } else if (good (buf)) {
  1295.             if (rootword[0] == 0) {
  1296.                 printf ("*\n");    /* perfect match */
  1297.             } else {
  1298.                 printf ("+ %s\n", rootword);
  1299.             }
  1300.         } else {
  1301.             makepossibilities (buf);
  1302.             if (possibilities[0][0]) {
  1303.                 printf ("& ");
  1304.                 for (i = 0; i < MAXPOSSIBLE; i++) {
  1305.                     if (possibilities[i][0] == 0)
  1306.                         break;
  1307.                     printf ("%s ", possibilities[i]);
  1308.                 }
  1309.                 printf ("\n");
  1310.             } else {
  1311.                 printf ("#\n");
  1312.             }
  1313.         }
  1314. #if !defined(USG) && !defined(atarist)
  1315.         if (sflag) {
  1316.             stop ();
  1317.             if (fflag) {
  1318.                 rewind (stdout);
  1319.                 creat (askfilename, 0666);
  1320.             }
  1321.         }
  1322. #endif
  1323.     }
  1324. }
  1325.  
  1326. /* Copy/ignore "cnt" number of characters pointed to by *cc. */
  1327. copyout(cc, cnt)
  1328. register char    **cc;
  1329. register cnt;
  1330. {
  1331.     while (--cnt >= 0) {
  1332.         if (*(*cc) == 0)
  1333.             break;
  1334.         if (!lflag)
  1335.             putc (*(*cc), outfile);
  1336.         (*cc)++;
  1337.     }
  1338. }
  1339.  
  1340. lookharder(string)
  1341. char *string;
  1342. {
  1343.     char cmd[150], grepstr[100];
  1344.     register char *g, *s;
  1345.     register int wild = 0;
  1346.  
  1347.     g = grepstr;
  1348.     for (s = string; *s != '\0'; s++)
  1349.         if (*s == '*') {
  1350.             wild++;
  1351.             *g++ = '.';
  1352.             *g++ = '*';
  1353.         } else
  1354.             *g++ = *s;
  1355.     *g = '\0';
  1356.     if (grepstr[0]) {
  1357. #ifdef LOOK
  1358.         if (wild)
  1359.             /* string has wild card characters */
  1360.             sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
  1361.         else
  1362.             /* no wild, use look(1) */
  1363.             sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
  1364. #else
  1365.         sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
  1366. #endif
  1367.         shellescape (cmd);
  1368.     }
  1369. }
  1370.